package com.sxhuayuan.parking.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sxhuayuan.parking.compenent.Message;
import com.sxhuayuan.parking.compenent.Page;
import com.sxhuayuan.parking.compenent.Pageable;
import com.sxhuayuan.parking.compenent.shiro.AccountType;
import com.sxhuayuan.parking.compenent.shiro.Principal;
import com.sxhuayuan.parking.compenent.web.RespMessage.Status;
import com.sxhuayuan.parking.dao.AdminDao;
import com.sxhuayuan.parking.dao.BaseDao;
import com.sxhuayuan.parking.entity.Admin;
import com.sxhuayuan.parking.entity.Agent;
import com.sxhuayuan.parking.entity.Role;
import com.sxhuayuan.parking.exception.MyException;
import com.sxhuayuan.parking.service.AdminService;
import com.sxhuayuan.parking.service.RoleService;

@Service("adminServiceImpl")
public class AdminServiceImpl extends BaseServiceImpl<Admin, Long> implements AdminService {

	Logger log = LoggerFactory.getLogger(getClass());

	@Autowired
	AdminDao adminDao;


	@Override
	public BaseDao<Admin, Long> getDAO() {
		return adminDao;
	}

	@Transactional(readOnly = true)
	public boolean usernameExists(String username) {
		return adminDao.count((Root<Admin> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) -> {
			return criteriaBuilder.equal(root.get("username"), username);
		}) > 0;
	}

	@Transactional(readOnly = true)
	public Admin findByUsername(String username) {
		return adminDao.findByUsername(username);
	}

	@Transactional(readOnly = true)
	public List<String> findAuthorities(Long id) {
		List<String> authorities = new ArrayList<String>();
		Admin admin = adminDao.findById(id).get();
		if (admin != null) {
			for (Role role : admin.getRoles()) {
				authorities.addAll(role.getAuthorities());
			}
		}
		return authorities;
	}

	@Transactional(readOnly = true)
	public boolean isAuthenticated() {
		Subject subject = SecurityUtils.getSubject();
		if (subject != null && subject.getPrincipal() != null) {
			Principal principal = (Principal) subject.getPrincipal();
			if (principal.getType() == AccountType.admin) {
				return subject.isAuthenticated();
			}
		}
		return false;
	}

	@Transactional(readOnly = true)
	public Admin getCurrent() {
		Subject subject = SecurityUtils.getSubject();
		if (subject != null && subject.getPrincipal() != null) {
			Principal principal = (Principal) subject.getPrincipal();
			if (principal.getType() == AccountType.admin) {
				return adminDao.findById(principal.getId()).get();
			}
		}
		return null;

	}

	@Transactional(readOnly = true)
	public String getCurrentName() {
		Subject subject = SecurityUtils.getSubject();
		if (subject != null && subject.getPrincipal() != null) {
			Principal principal = (Principal) subject.getPrincipal();
			if (principal.getType() == AccountType.admin) {
				return principal.getUsername();
			}
		}
		return null;
	}

	@Transactional(readOnly = true)
	public String getCurrentUsername() {
		Subject subject = SecurityUtils.getSubject();
		if (subject != null) {
			Principal principal = (Principal) subject.getPrincipal();
			if (principal != null) {
				return principal.getUsername();
			}
		}
		return null;
	}

	@Override
	@Transactional
	@CacheEvict(value = { "adminAuthorization", "commonData" }, allEntries = true)
	public void save(Admin admin) {
		try {
			super.save(admin);
		} catch (org.springframework.dao.DataIntegrityViolationException e) {
			throw new MyException(Status.ERROR, Message.FORM_USERNAME_EXISTS);
		}
	}

	@Override
	@Transactional
	@CacheEvict(value = { "adminAuthorization", "commonData" }, allEntries = true)
	public Admin update(Admin admin) {
		if (Objects.isNull(admin.getId())) {
			throw new MyException(Status.VALID_ERR, Message.FORM_VALID_FAIL);
		}
		try {
			return super.update(admin);
		} catch (org.springframework.dao.DataIntegrityViolationException e) {
			throw new MyException(Status.ERROR, Message.FORM_USERNAME_EXISTS);
		}
	}

	@Override
	@Transactional
	@CacheEvict(value = { "adminAuthorization", "commonData" }, allEntries = true)
	public void delete(Long id) {
		super.delete(id);
	}

	@Override
	@Transactional
	@CacheEvict(value = { "adminAuthorization", "commonData" }, allEntries = true)
	public void delete(Long... ids) {
		super.delete(ids);
	}

	@Override
	@Transactional
	@CacheEvict(value = { "adminAuthorization", "commonData" }, allEntries = true)
	public void delete(Admin admin) {
		super.delete(admin);
	}

	/**
	 * 分页查询
	 */
	@Override
	public Page<Admin> findPage(Pageable pageable) {
		Specification<Admin> specification = new Specification<Admin>() {

			private static final long serialVersionUID = 1L;

			@Override
			public Predicate toPredicate(Root<Admin> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				Predicate predicate = cb.conjunction();
				// 查询排除超级管理员
				Join<Agent, Role> join = root.join("roles");
				predicate = cb.and(predicate, cb.equal(join.get("isSystem"), false));
				return predicate;
			}

		};

		return super.findPage(pageable, specification);
	}

	/**
	 * 锁定启用
	 */
	@Override
	public void onIsLockedAndEnabled(Long id, String type, Boolean value) {
		Admin admin = this.findOne(id);
		if (Objects.isNull(admin)) {
			throw new MyException(Status.VALID_ERR, Message.FORM_VALID_FAIL);
		}
		if ("Locked".equals(type)) {
			admin.setIsLocked(value);
		}
		if ("Enabled".equals(type)) {
			admin.setIsEnabled(value);
		}
		adminDao.save(admin);
	}
}
